﻿#region Imports
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
#endregion

namespace CommonUtilities.Util
{
    /// <summary>
    /// Hashing utility
    /// </summary>
    public static class HashUtil
    {
        #region Declarations
        /// <summary>
        /// Hash to be displayed when not desired to calculate
        /// </summary>
        public const string DEFAULT_HASH = "N/A";
        #endregion

        #region Methods
        public static byte[] OtherHash(string filePath)
        {
            byte[] hashBytes;
            using (var inputFileStream = File.OpenRead(filePath))
            {
                var md5 = MD5.Create();
                hashBytes = md5.ComputeHash(inputFileStream);

                // -- OR --
                byte[] data = Encoding.UTF8.GetBytes(filePath);
                byte[] hash = SHA512.Create().ComputeHash(data);
            }

            return hashBytes;
        }

        #region SHA256 Hashing
        public static string GetHashCode(string filePath, bool skipHash)
        {
            // Hash to be displayed when not desired to calculate
            if (skipHash) return DEFAULT_HASH;

            using (FileStream stream = File.OpenRead(filePath))
            {
                SHA256Managed sha = new SHA256Managed();
                byte[] hash = sha.ComputeHash(stream);
                return BitConverter.ToString(hash).Replace("-", String.Empty);
            }
        }
        #endregion

        #region SHA1 Hashing
        /// <summary>
        /// Gets a hash of the file using SHA1
        /// </summary>
        /// <param name="filePath"></param>
        /// <returns></returns>
        public static string GetSHA1Hash(string filePath)
        {
            using (var sha1 = new SHA1CryptoServiceProvider())
                return GetHash(filePath, sha1);
        }

        /// <summary>
        /// Gets a hash of the file using SHA1
        /// </summary>
        /// <param name="filePath"></param>
        /// <returns></returns>
        public static string GetSHA1Hash(Stream s)
        {
            using (var sha1 = new SHA1CryptoServiceProvider())
                return GetHash(s, sha1);
        }
        #endregion

        #region MD5 Hashing
        /// <summary>
        /// Gets a hash of the file using MD5
        /// </summary>
        /// <param name="filePath"></param>
        /// <returns></returns>
        public static string GetMD5Hash(string filePath)
        {
            using (var md5 = new MD5CryptoServiceProvider())
                return GetHash(filePath, md5);
        }

        /// <summary>
        /// Gets a hash of the file using MD5
        /// </summary>
        /// <param name="filePath"></param>
        /// <returns></returns>
        public static string GetMD5Hash(Stream s)
        {
            using (var md5 = new MD5CryptoServiceProvider())
                return GetHash(s, md5);
        }
        #endregion

        private static string GetHash(string filePath, HashAlgorithm hasher)
        {
            using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                return GetHash(fs, hasher);
        }

        private static string GetHash(Stream s, HashAlgorithm hasher)
        {
            var hash = hasher.ComputeHash(s);
            var hashStr = Convert.ToBase64String(hash);
            return hashStr.TrimEnd('=');
        }
        #endregion
    }
}
